package com.ptswitch.material.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.tapestry5.upload.services.UploadedFile;
import org.hxzon.tapestry5.util.FileStreamResponse;
import org.hxzon.util.DateFormatUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ptswitch.material.model.base.Upload;
import com.ptswitch.material.model.common.LoginInfo;

public class WebUtil {
    private static Logger logger = LoggerFactory.getLogger(WebUtil.class);

    public static final int cookieTime = 3600 * 24 * 14;
    public static final String cookieName_Username = "username";
    public static final String cookieName_LoginToken = "loginToken";

    // file:/d:/xxx
    //myapp/WEB-INF/classes
    private String webappPath;
    private String savePath;

    public WebUtil(ServletContext servletContext) {
        webappPath = servletContext.getRealPath("");
        logger.info("contextPath:" + webappPath);
        if (webappPath == null) {
            webappPath = "";
        }
        savePath = webappPath + "/WEB-INF/upload/";
    }

    public static Cookie addCookie(String name, String value, String path) {
        Cookie cookie = new Cookie(name, value);
        cookie.setPath(path);
        cookie.setMaxAge(cookieTime);
        return cookie;
    }

    public static Cookie addCookie(String name, String value) {
        return addCookie(name, value, "/");
    }

    public static Cookie addUsernameCookie(String value) {
        return addCookie(cookieName_Username, value);
    }

    public static Cookie addLoginTokenCookie(String value) {
        return addCookie(cookieName_LoginToken, value);
    }

    public static LoginInfo getLoginInfoCookie(Cookie cookies[]) {
        LoginInfo loginInfo = new LoginInfo();
        for (Cookie cookie : cookies != null ? cookies : new Cookie[0]) {
            logger.trace("cookie [" + cookie.getName() + ":" + cookie.getValue() + "]:" + cookie.getPath());
            if (cookie.getName().equals(cookieName_Username)) {
                loginInfo.setUsername(cookie.getValue());
                logger.trace("cookie login:{}", loginInfo.getUsername());
            } else if (cookie.getName().equals(cookieName_LoginToken)) {
                loginInfo.setId(cookie.getValue());
            }
        }
        return loginInfo;
    }

    public <U extends Upload> List<U> upload(Collection<UploadedFile> files, Class<U> clazz) {
        List<U> uploads = new ArrayList<U>();
        U upload;
        for (UploadedFile file : files) {
            String newFileName = generateFileName(file.getFileName());
            try {
                IOUtils.copy(file.getStream(), FileUtils.openOutputStream(new File(generateUploadFilePath(clazz, newFileName))));
                upload = clazz.newInstance();
                upload.setFileName(file.getFileName());
                upload.setFilePath(newFileName);
                upload.setFileType(file.getContentType());
                upload.setCreateTime(DateFormatUtil.formatToUniteTime(new Date()));
                // upload.setUser(visitor());
                uploads.add(upload);
                logger.info("upload file {} ,{}", upload.getFileName(), getRealFilePath(upload));
            } catch (IOException e) {
                logger.error("上传文件出错", e);
            } catch (InstantiationException e) {
                logger.error("上传文件出错", e);
            } catch (IllegalAccessException e) {
                logger.error("上传文件出错", e);
            }
        }
        return uploads;
    }

    public <U extends Upload> U upload(UploadedFile file, Class<U> clazz) {
        if (file == null) {
            return null;
        }
        //note:if not null,the filename always not null and not empty
        String newFileName = generateFileName(file.getFileName());
        U upload = null;
        try {
            // FileUtils.copyFile(new File(file.getFilePath()), new
            // File(WebUtil.savePath + newFileName), true);
            IOUtils.copy(file.getStream(), FileUtils.openOutputStream(new File(generateUploadFilePath(clazz, newFileName))));
            upload = clazz.newInstance();
            upload.setFileName(file.getFileName());
            upload.setFilePath(newFileName);
            upload.setFileType(file.getContentType());
            upload.setCreateTime(DateFormatUtil.formatToUniteTime(new Date()));
            logger.info("upload file {} ,{}", upload.getFileName(), getRealFilePath(upload));
        } catch (IOException e) {
            logger.error("上传文件出错", e);
        } catch (InstantiationException e) {
            logger.error("上传文件出错", e);
        } catch (IllegalAccessException e) {
            logger.error("上传文件出错", e);
        }
        return upload;
    }

    protected static String generateFileName(String fileName) {
        DateFormat format = new SimpleDateFormat("yyMMddHHmmss");
        String formatDate = format.format(new Date());

        int position = fileName.lastIndexOf(".");
        String extension = fileName.substring(position);
        return fileName + formatDate + extension;
    }

    public FileStreamResponse download(Upload upload) {

        // Upload upload = uploadSer.get(id);
        InputStream targetFile = null;
        try {
            targetFile = FileUtils.openInputStream(new File(getRealFilePath(upload)));
            return new FileStreamResponse(targetFile, upload.getFileName(), upload.getFileType());
        } catch (Exception e) {
            logger.error("文件不存在:{}", e.getMessage());
        }
        if (targetFile == null) {
            targetFile = IOUtils.toInputStream("文件已被删除");
        }
        return new FileStreamResponse(targetFile, "notexist.txt", "text/plain");
    }

    public void delete(Upload upload) {
        FileUtils.deleteQuietly(new File(getRealFilePath(upload)));
    }

    public String getWebappPath() {
        return webappPath;
    }

    public String getSavePath() {
        return savePath;
    }

    public String getRealFilePath(Upload upload) {
        return savePath + upload.getClass().getSimpleName() + "/" + upload.getFilePath();
    }

    public String generateUploadFilePath(Class<? extends Upload> clazz, String newFileName) {
        return savePath + clazz.getSimpleName() + "/" + newFileName;
    }
}
